import * as THREE from 'three'
import * as SkeletonUtils from 'three/examples/jsm/utils/SkeletonUtils.js';
import { huanJing } from '../../huanJing/HuanJing.js'
import { gengXinJiHe } from '../../gengXin/gengXin.js'
import { wuTiCaoZuo, wuLiWorker } from '../../wuLi/WuLiWorker.js'
import { jiaZaiZiYuan } from '../../jiaZaiZiYuan/jiaZaiZiYuan.js'
import { WuTi } from './WuTi.js'

// 物体默认刚体
class GangTi extends WuTi {
	dongHuaBoFangQi = null
	dongHua = []
	
	zhiLiang = null
	wuTiLeiXing = '刚体' // 默认刚体
	shiGangTi = true
	yinLiJuLi = 0 // 引力作用距离
	#pengZhuangZhuangTai = false // 物理碰撞状态
	pengZhuangTi = null
	xingZhuang = null
	tongBuWuLi = true // 是否从物理世界同步状态
	
	yueShu = new Set() // 约束
	
	jiaZaiJuLi = 100 // 加载距离 小于此值加载
	jiaZaiZhuangTai = false // true：已加载， false：未加载
	fu = null // 父物体
	zi = new Set() // 子物体
	;['shouLiXingXing'] = null // 受力行星
	zhongLi = null
	
	/**
	 * @param {Mesh} moXing 模型
	 * @param {Group|Mesh|Object} pengZhuangTi 碰撞体
	 * @param {String} pengZhuangTi.userData.xingZhuang 形状
	 * @param {Number} zhiLiang 质量; 0为静态物体
	 */
	constructor(moXing, pengZhuangTi, zhiLiang = 0) {
		super(moXing)
		
		Object.defineProperty(this, 'zhiLiang', {
			value: zhiLiang,
			writable: true
		})
		
		this.dongHuaBoFangQi = new THREE.AnimationMixer(this.moXing)
		this.pengZhuangTi = pengZhuangTi
		this.xingZhuang = pengZhuangTi.userData.xingZhuang
	}
	
	/**
	 * 加载模型文件
	 * @param {String|Mesh} canShu
	 */
	async jiaZaiMoXing(canShu) {
		let moXing = null
		let animations = null
		if (typeof canShu == 'string') {
			let res = await jiaZaiZiYuan(canShu)
			res.scene.traverse(wangGe => {
				wangGe.castShadow = true
				wangGe.receiveShadow = true
				// 根据透明度投影
				if(wangGe.name.includes('shuYe')) {
					let material = new THREE.MeshStandardMaterial( {
						side: THREE.DoubleSide,
						map: wangGe.material.map,
						alphaMap: wangGe.material.map, // 黑色为透明
						alphaTest: 0.1
					} )
					wangGe.material = material
				}
			})
			moXing = res.scene
			animations = res.animations
		}
		if (canShu.isMesh) {
			moXing = canShu
			animations = canShu.animations
		}
		
		let jiuMoXing = this.moXing
		this.moXing = moXing
		let { position, quaternion, scale } = this.moXing
		moXing.matrix.decompose(position, quaternion, scale)
		let parent = jiuMoXing.parent || huanJing.scene
		let children = [...jiuMoXing.children]
		jiuMoXing.removeFromParent()
		if (children.length > 0) moXing.add(...children)
		parent.add(this.moXing)
		this.dongHuaBoFangQi = new THREE.AnimationMixer(this.moXing)
		this.dongHua = []
		this.tianJiaDongHua(animations)
		
		this.chuFaShiJian({ leiXing: 'jiaZaiMoXing' })
	}
	// 把剪辑变成动画
	tianJiaDongHua(dongHuaJianJi) {
		for (let i = 0, l = dongHuaJianJi.length; i < l; i++) {
			let dongHua = this.dongHuaBoFangQi.clipAction(dongHuaJianJi[i])
			dongHua.play()
			dongHua.setEffectiveWeight(0)
			this.dongHua.push(dongHua)
		}
	}
	// 处理碰撞体
	chuLiPengZhuangTi(pzt) {
		let xingZhuang = pzt.userData.xingZhuang
		let suoFang = new Float64Array(pzt.scale.toArray())
		let xuanZhuan = new Float64Array(pzt.quaternion.toArray())
		let weiZhi = new Float64Array(pzt.position.toArray())
		let jieGuo = { xingZhuang, suoFang, xuanZhuan, weiZhi }
	
		if (xingZhuang == '组合') jieGuo.zi = pzt.children.map(p => this.chuLiPengZhuangTi(p))
		else {
			let geometry = pzt.geometry
			geometry.computeBoundingBox()
			geometry.computeBoundingSphere()
			// 由threejs对应的geometry生成
			if (xingZhuang == '方体' || xingZhuang == '球体' || xingZhuang == '胶囊' || xingZhuang == '圆锥' || xingZhuang == '圆柱') jieGuo.chiCun = geometry.parameters
			if (xingZhuang == '方体') jieGuo.fangTi = geometry.boundingBox
			if (xingZhuang == '球体') jieGuo.qiuTi = geometry.boundingSphere
			if (xingZhuang == '地形') {
				// PlaneGeometry生成
				jieGuo.chiCun = geometry.parameters
				jieGuo.diXing = geometry.attributes.position.array
			}
			if (xingZhuang == '静三角' || xingZhuang == '动三角' || xingZhuang == '凸几何') {
				geometry = geometry.index !== null ? geometry.toNonIndexed() : geometry
				jieGuo.dingDian = geometry.attributes.position.array
			}
		}
	
		return jieGuo
	}
	// 添加碰撞体进物理引擎
	tianJiaPengZhuangTi() {
		if (!this.pengZhuangTi) return // 自动插入分号
		this.pengZhuangZhuangTai = true
	
		let caoZuo = {
			mingZi: 'tianJiaWuTi',
			canShu: {
				wuTiLeiXing: this.wuTiLeiXing,
				bianHao: this.bianHao,
				mingZi: this.mingZi,
				zhiLiang: this.zhiLiang,
				suoFang: this.moXing.scale.toArray(),
				xuanZhuan: this.moXing.getWorldQuaternion(new THREE.Quaternion()).toArray(),
				weiZhi: this.moXing.getWorldPosition(new THREE.Vector3()).toArray(),
				pengZhuangTi: null
			}
		}
		caoZuo.canShu.pengZhuangTi = this.chuLiPengZhuangTi(this.pengZhuangTi)
		wuTiCaoZuo[this.bianHao] = [caoZuo]
	}
	// 移除碰撞体出物理引擎
	yiChuPengZhuangTi() {
		if (!this.pengZhuangTi) return
		this.pengZhuangZhuangTai = false
		
		let caoZuo = { mingZi: 'yiChuWuTi', canShu: { bianHao: this.bianHao } }
		if (wuTiCaoZuo[this.bianHao]) wuTiCaoZuo[this.bianHao].push(caoZuo)
	}
	/**
	 * 设置碰撞体 本地坐标需转世界坐标
	 */
	sheZhiPengZhuangTi(sheZhiCanShu) {
		if (!this.pengZhuangZhuangTai) return
		let caoZuoShuZu = wuTiCaoZuo[this.bianHao]

		if (caoZuoShuZu) {
			let sheZhiCaoZuo = caoZuoShuZu.find(caoZuo => caoZuo.mingZi == 'sheZhiWuTi')
			if (sheZhiCaoZuo) {
				let canShu = sheZhiCaoZuo.canShu
				canShu.bianHao = this.bianHao
				canShu.mingZi = this.mingZi
				// 同一帧的操作后面会覆盖前面
				if (sheZhiCanShu.suoFang) canShu.suoFang = sheZhiCanShu.suoFang.toArray()
				if (sheZhiCanShu.xuanZhuan) canShu.xuanZhuan = sheZhiCanShu.xuanZhuan.toArray()
				if (sheZhiCanShu.weiZhi) canShu.weiZhi = sheZhiCanShu.weiZhi.toArray()
				if (sheZhiCanShu.xianSuDu) canShu.xianSuDu = sheZhiCanShu.xianSuDu.toArray()
				if (sheZhiCanShu.jiaXianSuDu) canShu.jiaXianSuDu = sheZhiCanShu.jiaXianSuDu.toArray()
				if (sheZhiCanShu.jiaoSuDu) canShu.jiaoSuDu = sheZhiCanShu.jiaoSuDu.toArray()
				if (sheZhiCanShu.shouLi) canShu.shouLi = sheZhiCanShu.shouLi.toArray()
				if (sheZhiCanShu.chongLiang) canShu.chongLiang = sheZhiCanShu.chongLiang.toArray()
				if (sheZhiCanShu.zhongLi) canShu.zhongLi = sheZhiCanShu.zhongLi.toArray()
				if (sheZhiCanShu.moCa !== undefined) canShu.moCa = sheZhiCanShu.moCa
				if (sheZhiCanShu.xianZuLi !== undefined) canShu.xianZuLi = sheZhiCanShu.xianZuLi
				if (sheZhiCanShu.jiaoZuLi !== undefined) canShu.jiaoZuLi = sheZhiCanShu.jiaoZuLi
			} else {
				let caoZuo = {
					mingZi: 'sheZhiWuTi',
					canShu: {
						bianHao: this.bianHao,
						mingZi: this.mingZi,
						suoFang: sheZhiCanShu.suoFang?.toArray(),
						xuanZhuan: sheZhiCanShu.xuanZhuan?.toArray(),
						weiZhi: sheZhiCanShu.weiZhi?.toArray(),						
						xianSuDu: sheZhiCanShu.xianSuDu?.toArray(),
						jiaXianSuDu: sheZhiCanShu.jiaXianSuDu?.toArray(),
						jiaoSuDu: sheZhiCanShu.jiaoSuDu?.toArray(),
						shouLi: sheZhiCanShu.shouLi?.toArray(),
						chongLiang: sheZhiCanShu.chongLiang?.toArray(),
						zhongLi: sheZhiCanShu.zhongLi?.toArray(),
						moCa: sheZhiCanShu.moCa,
						xianZuLi: sheZhiCanShu.xianZuLi,
						jiaoZuLi: sheZhiCanShu.jiaoZuLi
					}
				}
				
				wuTiCaoZuo[this.bianHao].push(caoZuo)
			}
		}
	}
	/**
	 * 编辑组合形状的子形状
	 * @param {Object} bianJiCanShu
	 * @param {Number} bianJiCanShu.bianJiLeiXing 0 添加，1 设置，2 删除
	 * @param {Mesh} bianJiCanShu.moXing
	 */
	bianJiXingZhuang(bianJiCanShu) {
		if (!this.pengZhuangZhuangTai || this.xingZhuang !== '组合') return

		let { moXing, pengZhuangTi, bianJiLeiXing } = bianJiCanShu

		let caoZuoShuZu = wuTiCaoZuo[this.bianHao]

		if (caoZuoShuZu) {
			let caoZuo = {
				mingZi: 'bianJiXingZhuang',
				canShu: {
					bianHao: this.bianHao,
					mingZi: this.mingZi,
					bianJiLeiXing
				}
			}

			if (bianJiLeiXing === 0) {
				pengZhuangTi.position.copy(moXing.position)
				moXing.userData.huoQuWuTi = () => this
				this.moXing.add(moXing)
				this.pengZhuangTi.add(pengZhuangTi)

				caoZuo.canShu.pengZhuangTi = this.chuLiPengZhuangTi(pengZhuangTi)
			} else {
				for (let i = 0, l = this.pengZhuangTi.children.length; i < l; i++) {
					let a = this.pengZhuangTi.children[i]
					if (a.uuid === moXing.userData.pengZhuangTiUUID) {
						pengZhuangTi = a
						caoZuo.canShu.suoYin = i
						break
					}
				}

				if (bianJiLeiXing === 1) {
					// 模型与碰撞体局部变换需相同
					pengZhuangTi.matrix.copy(moXing.matrix)
					pengZhuangTi.matrix.decompose( pengZhuangTi.position, pengZhuangTi.quaternion, pengZhuangTi.scale )

					caoZuo.canShu.sheZhi = {
						suoFang: new Float64Array(pengZhuangTi.scale.toArray()),
						xuanZhuan: new Float64Array(pengZhuangTi.quaternion.toArray()),
						weiZhi: new Float64Array(pengZhuangTi.position.toArray())
					}
				}
	
				if (bianJiLeiXing === 2) {
					moXing.removeFromParent()
					pengZhuangTi.removeFromParent()
	
					if (this.pengZhuangTi.children.length == 0) this.xiaoHui()
				}
	
			}
			
			let qianCaoZuo = caoZuoShuZu.find(caoZuo => (caoZuo.mingZi == 'bianJiXingZhuang' && caoZuo.canShu.bianJiLeiXing == bianJiLeiXing))

			if (qianCaoZuo) Object.assign(qianCaoZuo, caoZuo)
			else caoZuoShuZu.push(caoZuo)
		}
	}
	
	set pengZhuangZhuangTai(canShu) {
		this.#pengZhuangZhuangTai = canShu
	}
	get pengZhuangZhuangTai() {
		return this.#pengZhuangZhuangTai
	}
	
	// 所受引力
	// 引力物体多 性能会很低
	// shouYinLi() {
	// 	let yinLiWuTi = WuTi.quanBuWuTi.filter(w => w.yinLiJuLi > 0 && w != this)
	
	// 	yinLiWuTi.forEach(w => {
	// 		let juLi = w.moXing.position.distanceTo(this.moXing.position)
	// 		if (juLi < w.yinLiJuLi) {
	// 			const G = 6.67259e-11
	// 			let yinLi = G * w.zhiLiang * this.zhiLiang / (juLi ** 2) // 万有引力公式
	// 			let xianSuDu = Math.sqrt(G * w.zhiLiang / juLi) // 公转线速度公式
	
	// 			let li = new THREE.Vector3().subVectors(w.moXing.position, this.moXing.position).normalize().multiplyScalar(yinLi)
	
	// 			this.sheZhiPengZhuangTi({ shouLi: li })
	// 		}
	// 	})
	// }
	
	// 受行星的重力
	shouZhongLi() {
		if (this.shiXingXing || this.shiHengXing) return
		let quanBuWuTi = WuTi.quanBuWuTi
		let zuiDuanjuLi = Infinity
		let xingXing = null
		let zhongLi = null
		let ziShenWeiZhi = new THREE.Vector3() // 自身位置
		let xingXingWeiZhi = new THREE.Vector3() // 行星位置
		let fangXiang = new THREE.Vector3()
		this.moXing.getWorldPosition(ziShenWeiZhi)
		for (let i = 0, il = quanBuWuTi.length; i < il; i++) {
			let wuTi = quanBuWuTi[i]
			if (!wuTi.shiXingXing) continue
			let weiZhi = new THREE.Vector3()
			wuTi.moXing.getWorldPosition(weiZhi)
			let juLi = ziShenWeiZhi.distanceTo(weiZhi)
			if (juLi < zuiDuanjuLi && juLi < wuTi.yinLiJuLi) {
				xingXingWeiZhi = weiZhi
				zuiDuanjuLi = juLi
				xingXing = wuTi
			}
		}
		this.shouLiXingXing = xingXing
		if (xingXing) {
			zhongLi = fangXiang.subVectors(xingXingWeiZhi, ziShenWeiZhi).normalize().multiplyScalar(xingXing.zhongLiJiaSuDu)
			this.sheZhiPengZhuangTi({ zhongLi })
		} else {
			this.sheZhiPengZhuangTi({ zhongLi: new THREE.Vector3(0, 0, 0) })
		}
		this.zhongLi = zhongLi
	}
	// 添加进父行星物体，初始速度
	chuSuDu() {
		 // 设置初始速度，防止滚动；行星角速度没计算进去
		if (this.fu && this.fu.xianSuDu) {
			this.sheZhiPengZhuangTi({ xianSuDu: this.fu.xianSuDu })
		}
	}
	
	// 从物理引擎同步数据
	tongBu(wuTiCanShu) {
		if (!this.tongBuWuLi || wuLiWorker.tingZhiMoNiZhuangTai) return

		let { weiZhi, xuanZhuan } = wuTiCanShu

		// 缩放 旋转 平移 固定顺序
		// 同步旋转
		// 此处不能更新世界矩阵
		const thQ = new THREE.Quaternion()
		const thQ2 = new THREE.Quaternion()
		const thQ3 = new THREE.Quaternion()
		thQ.set(...xuanZhuan)
		thQ2.setFromRotationMatrix( this.moXing.matrixWorld )
		thQ2.conjugate()
		thQ2.multiply( thQ )
		thQ3.setFromRotationMatrix( this.moXing.matrix )
		this.moXing.quaternion.copy(thQ3.multiply( thQ2 ).normalize()) // 右乘左乘 此处写的不确定
		
		// 同步位置
		let xiangLiang = new THREE.Vector3()
		xiangLiang.set(...weiZhi)
		this.moXing.position.copy(this.moXing.parent.worldToLocal(xiangLiang))
	}
	// 帧更新
	gengXin(jianGeShi) {
		this.dongHuaBoFangQi?.update(jianGeShi)
		
		this.shouZhongLi()
		
		this.xiaCiGengXinHou()
		this.xiaCiGengXinHou = () =>{}
	}
	// 赋值：操作物理物体，同步更新后，要运行的方法
	xiaCiGengXinHou() {}
	// 加载物体，加载模型进父模型
	jiaZai() {
		if (this.jiaZaiZhuangTai) return
		
		if (this.yueShu.size > 0) {
			this.tianJiaJianTingQi('tianJiaWuTi', shiJian => {
				shiJian.muBiao.xiaCiGengXinHou = () => {
					this.yueShu.forEach(y => y.jiaZai())
				}
			})
		}

		this.jiaZaiZhuangTai = true
		let fuMoXing = this.fu?.moXing ?? huanJing.scene
		fuMoXing.add(this.moXing)
		this.tianJiaPengZhuangTi()
		WuTi.quanBuWuTi.push(this)
		this.chuSuDu()
		gengXinJiHe.set(this, this.gengXin.bind(this))
	}
	// 卸载物体
	xieZai() {
		if (this.yueShu.size > 0) this.yueShu.forEach(y => y.xieZai())
		
		this.jiaZaiZhuangTai = false
		this.moXing.removeFromParent()
		this.yiChuPengZhuangTi()
		gengXinJiHe.delete(this)
		let suoYin = WuTi.quanBuWuTi.findIndex(w => w == this)
		if (suoYin > -1) WuTi.quanBuWuTi.splice(suoYin, 1)
	}
	// 销毁物体
	xiaoHui() {
		this.xieZai()
		
		if (this.fu) this.fu.zi.delete(this)
		
		function xh(a) {
			a.geometry?.dispose()
			
			if (Array.isArray( a.material )) {
				a.material.forEach(b => {
					b.material?.map?.dispose()
					b.material?.dispose()
				})
			} else {
				a.material?.map?.dispose()
				a.material?.dispose()
			}
		}
		this.moXing.traverse(xh)
		this.pengZhuangTi?.traverse(xh)
	}
	// 复制物体
	fuZhi() {
		let moXing = SkeletonUtils.clone(this.moXing)
		let pengZhuangTi = this.pengZhuangTi && SkeletonUtils.clone(this.pengZhuangTi)
		return new this.constructor(moXing, pengZhuangTi, this.zhiLiang)
	}
	
}

export {
	GangTi
}